package com.luo.config;

import com.google.common.io.CountingInputStream;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.text.SimpleDateFormat;
import java.util.Date;

/**
 * Controller层日志
 * @author Luo
 */
@Aspect
@Component
public class WebLogAspect {
    private Logger logger = LoggerFactory.getLogger(getClass());
    private String time;
    private String agent;
    private String level;
    private long dataSize;
    private String ip;
    private String method;
    private String path;
    private long spendTime;
    private String hostName;
    private int status;

    ThreadLocal<Long> startTime = new ThreadLocal<>();

    //获取用户真实ip
    /**
     * 获取Ip地址，多级反向代理
     * @param request
     * @return
     */
    public static String getIpaddr(HttpServletRequest request){
        String ip = request.getHeader("x-forwarded-for");
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("WL-Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("HTTP_CLIENT_IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("HTTP_X_FORWARDED_FOR");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddr();
            if("127.0.0.1".equals(ip) || "0:0:0:0:0:0:0:1".equals(ip)){
                //根据网卡取本机配置的IP
                InetAddress inet=null;
                try {
                    inet = InetAddress.getLocalHost();
                } catch (UnknownHostException e) {
                    e.printStackTrace();
                }
                ip= inet.getHostAddress();
            }
        }
        return ip;
    }

    @Pointcut("execution(public * com.luo.controller..*.*(..))")
    public void webLog(){}

    @Before("webLog()")
    public void doBefore(JoinPoint joinPoint) throws Throwable{

        startTime.set(System.currentTimeMillis());

        //接收到请求，记录请求内容
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();
        this.time = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date());
        //记录下请求内容
        //logger.info("------------------------------------------------");
        this.path = "/api"+request.getRequestURI();
        //logger.info("URL : " + request.getRequestURI());
        this.method = request.getMethod();
        //logger.info("HTTP_METHOD : " + request.getMethod());
        this.ip = getIpaddr(request);
        this.hostName = request.getServerName();
        //logger.info("IP : " + request.getRemoteAddr());
        this.agent = request.getHeader("User-Agent");
        /*后端查看调用方法的信息*/
        //logger.info("CLASS_METHOD : " + joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName());
        //logger.info("ARGS : " + Arrays.toString(joinPoint.getArgs()));
    }

    @AfterReturning(returning = "ret", pointcut = "webLog()")
    public void doAfterReturning(Object ret) throws Throwable{
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletResponse response = attributes.getResponse();
        //处理完请求，返回内容
        //logger.info("RESPONSE : " + ret);;
        String information;
        this.spendTime = System.currentTimeMillis() - startTime.get();
        this.status = response.getStatus();
        this.dataSize = response.toString().getBytes().length;
        if(response.getStatus()==200){
            this.level = "info";
        }else if(response.getStatus()>=500){
            this.level = "error";
        }else if(response.getStatus()>=400){
            this.level = "warn";
        }
        information ="Time=\""+ time +
                "\" Level=\""+ level+
                "\" Method="+ method +
                " Path=\""+ path +
                "\" Status=" + status +
                " SpendTime=\""+ spendTime+"ms"+
                "\" DataSize="+this.dataSize+
                " Ip=\""+this.ip+
                "\" HostName=\""+this.hostName+
                "\" Agent=\""+this.agent+"\""
        ;
        switch (this.level){
            case "info":
                logger.info(information);
                break;
            case "warn":
                logger.warn(information);
                break;
            case "error":
                logger.error(information);
            default:
                break;
        }
        //logger.info("STATUS："+response.getStatus());
        //logger.info("SPEND TIME : " + (System.currentTimeMillis() - startTime.get()));
        //logger.info("-------------------------------------------------");
    }

}
